class Vue {
  constructor(options) {
    //保存创建Vue实例的时候的选项对象
    this.$options = options;
    //保存数据对象
    this.$data = options.data;
    //初始化事件
    this.initEvents();
    //初始化生命周期
    this.initLifeCycle();
    this.callHook("beforeCreate");
    //初始化provide/inject系统
    this.initInjections();
    //初始化响应式系统
    this.initReactivity();
    this.callHook('created');
    //如果用户没有提供el参数，则不会继续执行，直接返回了，等待用户手工调用$mount方法
    if(!this.$options.el){
        return;
    }
    //获取CSS选择器对应的DOM元素
    this.$el = document.querySelector(this.$options.el);
    //判断有没有template选项
    let {template} = this.$options;
    //如果没有提供，则会使用
    if(!template){
        template=this.$el.outerHTML;
    }
    //开始编译模板
    this.compile(template);
  }
  initEvents() {
    console.log("初始化事件系统"); //this.$on $emit $off
  }
  initLifeCycle() {
    this._isMounted = false; //布尔值，表示当前实例是否已经挂载成功
    console.log("初始化生命周期");
  }
  callHook(hookName) {
    //执行参数对象上对应的钩子函数
    this.$options[hookName]?.();
  }
  initInjections() {
    console.log("初始化注入系统");
  }
  initReactivity() {
    //遍历data对象的所有的属性
    for (let key in this.$data) {
      let watchers = [];  
      //获取data对象此key的值
      let value = this.$data[key];
      //把data上的属性都代理到this,也就是vm,也就是Vue实例上
      Object.defineProperty(this, key, {
        get() {
          const watcher = ()=>{
              this.callHook("beforeUpdate");
              this.update();
              this.callHook("updated");
          }
          watchers.push(watcher);
          //收集依赖
          return value;
        },
        set(newValue) {
          value = newValue;
          //派发更新
          watchers.forEach(watcher=>watcher());
        },
      });
    }
  }
  compile(template){
    //把用户提供的模板字符编译成render函数
    //render负责执行后生成虚拟DOM,虚拟DOM就是用JS描述DOM的结构
    this.render = function(vm){
        return {
            type:'div',
            props:{id:'app'},
            children:vm.message// 我们在执行render方法的时候会进行依赖收集
        }
    }
    this.callHook('beforeMount');
    this.update();
    this.callHook('mounted');
  }
  update(){
    //调用render方法生成虚拟DOM
    let vdom = this.render(this);
    //根据虚拟DOM生成真实DOM
    let newEl = createElement(vdom);
    //获取老的真实DOM
    let oldEl= this.$el;
    //用新生成的真实DOM替换掉老的真实DOM
    oldEl.parentNode.replaceChild(newEl,oldEl);
    //把this.$l赋值为新的DOM
    this.$el=newEl;
  }
  $destroy(){
    this.callHook('beforeDestroy');
    this.callHook('destroyed');
  }
}
function createElement(vdom){
   //创建给定类型的DOM节点
   let element = document.createElement(vdom.type);//div
   //遍历虚拟DOM上的属性对象，给真实DOM赋属性值
   for(let key in vdom.props){
    element.setAttribute(key,vdom.props[key]);
   }
   //给元素的儿子赋值
   element.innerHTML = vdom.children;
   return element;
}